package com.google.code.struts2jruby;

import java.util.Map;

import ognl.OgnlRuntime;

import org.apache.struts2.dispatcher.Dispatcher;
import org.apache.struts2.impl.StrutsActionProxyFactory;
import org.jruby.runtime.builtin.IRubyObject;

import com.google.code.struts2jruby.ognl.JRubyCompoundRootAccessor;
import com.google.code.struts2jruby.ognl.RubyObjectMethodAccessor;
import com.google.code.struts2jruby.ognl.RubyObjectPropertyAccessor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.DefaultActionProxy;
import com.opensymphony.xwork2.config.Configuration;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.CompoundRoot;

public class RubyStrutsActionProxyFactory extends StrutsActionProxyFactory {

	protected JRubyObjectFactory rubyFactory = new JRubyObjectFactory();
	private Configuration configuration;

	public RubyStrutsActionProxyFactory() {
		Container container = Dispatcher.getInstance().getContainer();
		container.inject(rubyFactory);
		OgnlRuntime.setPropertyAccessor(IRubyObject.class,
				new RubyObjectPropertyAccessor());
		OgnlRuntime.setMethodAccessor(IRubyObject.class,
				new RubyObjectMethodAccessor());
		OgnlRuntime.setMethodAccessor(CompoundRoot.class,
				new JRubyCompoundRootAccessor());
	}

	@Override
	public ActionProxy createActionProxy(ActionInvocation inv,
			String namespace, String actionName, Map extraContext,
			boolean executeResult, boolean cleanupContext) throws Exception {
		ActionInvocation invocation = new RubyDefaultActionInvocation(
				rubyFactory, extraContext, executeResult);
		DefaultActionProxy proxy = new RubyActionProxy(invocation,
				namespace, actionName, extraContext, executeResult, cleanupContext);
		container.inject(invocation);
		proxy.setConfiguration(configuration);
		proxy.prepare();
		container.inject(proxy);
		return proxy;
	}

	@Inject
	public void setContainer(Container container) {
		this.container = container;
	}

	@Inject
	public void setConfiguration(Configuration configuration) {
		this.configuration = configuration;
	}
}
